package com.whfc.emp.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.nacos.api.config.annotation.NacosValue;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.whfc.common.constant.QueueConst;
import com.whfc.common.enums.DeviceType;
import com.whfc.common.exception.BizException;
import com.whfc.common.file.FileHandler;
import com.whfc.common.file.FilePathConfig;
import com.whfc.common.file.properties.FileExpirationRules;
import com.whfc.common.result.PageData;
import com.whfc.common.result.ResultEnum;
import com.whfc.common.third.helmet.HelmetProperties;
import com.whfc.common.util.DateUtil;
import com.whfc.common.util.FileUtil;
import com.whfc.common.util.PageUtil;
import com.whfc.emp.dao.*;
import com.whfc.emp.dto.*;
import com.whfc.emp.entity.*;
import com.whfc.emp.enums.AppBroadcastSendState;
import com.whfc.emp.enums.AppBroadcastType;
import com.whfc.emp.helmet.ZbznApi;
import com.whfc.emp.helmet.ZbznVideoApi;
import com.whfc.emp.manager.AppEmpDataManager;
import com.whfc.emp.param.AppEmpBroadcastParam;
import com.whfc.emp.service.AppHelmetService;
import com.whfc.entity.dto.OssPathDTO;
import com.whfc.fuum.service.SysDeptService;
import com.whfc.hdc.dto.AppDeviceDTO;
import com.whfc.hdc.service.AppDeviceService;
import org.apache.commons.lang3.StringUtils;
import org.apache.dubbo.config.annotation.DubboReference;
import org.apache.dubbo.config.annotation.DubboService;
import org.apache.poi.hssf.usermodel.HSSFRow;
import org.apache.poi.hssf.usermodel.HSSFSheet;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.amqp.core.AmqpTemplate;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.ClassPathResource;
import org.springframework.scheduling.annotation.Scheduled;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.util.*;

/**
 * @Description 安全帽相关接口
 * @Author hw
 * @Date 2021/1/4 14:11
 * @Version 1.0
 */
@DubboService(interfaceClass = AppHelmetService.class, version = "1.0.0")
public class AppHelmetServiceImpl implements AppHelmetService {

    private Logger logger = LoggerFactory.getLogger(this.getClass());

    @DubboReference(interfaceClass = SysDeptService.class, version = "1.0.0")
    private SysDeptService sysDeptService;

    @DubboReference(interfaceClass = AppDeviceService.class, version = "1.0.0")
    private AppDeviceService appDeviceService;

    @Autowired
    private AppEmpMapper appEmpMapper;

    @Autowired
    private AppEmpDataMapper appEmpDataMapper;

    @Autowired
    private AppEmpGroupMapper appEmpGroupMapper;

    @Autowired
    private AppEmpDataManager appEmpDataManager;

    @Autowired
    private AppDeviceCardDataMapper appDeviceCardDataMapper;

    @Autowired
    private AppBroadcastRecordMapper appBroadcastRecordMapper;

    @Autowired
    private AppBroadcastRecordEmpMapper appBroadcastRecordEmpMapper;

    @Autowired
    private FilePathConfig msFilePathConfig;

    @Autowired
    private FileHandler fileHandler;

    @Autowired
    private AmqpTemplate amqpTemplate;

    @Autowired
    private ZbznVideoApi zbznVideoApi;

    @Override
    public PageData<AppDeviceCardLogDTO> getDeviceDataLog(String sn, Date startTime, Date endTime, Integer pageNum, Integer pageSize) {
        logger.info("查询安全帽硬件数据,sn:{},startTime:{},endTime:{},pageNum：{}，pageSize：{}", sn, startTime, endTime, pageNum, pageSize);
        AppDeviceDTO device = appDeviceService.getDeviceBySn(sn);
        if (device == null) {
            throw new BizException(ResultEnum.NOT_FOUND.getCode(), "设备不存在");
        }
        return appEmpDataManager.getHelmetDataLogByDeviceId(device.getId(), startTime, endTime, pageNum, pageSize);
    }

    @Override
    public AppDeviceCardDataDTO getDeviceData(Integer deviceId) throws BizException {
        AppDeviceCardData deviceData = appDeviceCardDataMapper.selectByDeviceId(deviceId);
        if (deviceData != null) {
            AppDeviceCardDataDTO cardDataDTO = new AppDeviceCardDataDTO();
            cardDataDTO.setTime(deviceData.getTime());
            cardDataDTO.setBatteryPower(deviceData.getBatteryPower());
            return cardDataDTO;
        }
        return null;
    }

    @Override
    public void broadcast(AppEmpBroadcastParam request) {
        logger.info("发送人员广播:request:{}", request);
        String content = request.getContent();
        if (content.length() > 100) {
            throw new BizException(ResultEnum.FAILURE.getCode(), "广播内容不能超过100个字符.");
        }
        Integer empId = request.getEmpId();
        Integer corpId = request.getCorpId();
        Integer groupId = request.getGroupId();
        Integer deptId = request.getDeptId();
        AppBroadcastRecord record = new AppBroadcastRecord();
        record.setContent(content);
        record.setDeptId(deptId);
        record.setSendUserId(request.getSendUserId());
        record.setSendUserName(request.getSendUserName());
        //取出人员
        if (empId == null) {
            record.setType(AppBroadcastType.DEPT.getValue());
        } else {
            record.setType(AppBroadcastType.EMP.getValue());
        }

        //保存记录
        appBroadcastRecordMapper.insertSelective(record);
        //保存广播人员
        if (empId == null) {
            //查找出组织机构下面的人员
            List<AppEmp> list = appEmpMapper.selectBindEmpByCorpIdOrGroupId(corpId, groupId, deptId);
            for (AppEmp appEmp : list) {
                saveRecordEmpAndSendBroadcast(record.getId(), content, appEmp,request.getVoiceType());
            }
        } else {
            //查找出人员信息
            AppEmp emp = appEmpMapper.selectByPrimaryKey(empId);
            if (emp == null) {
                throw new BizException(ResultEnum.FAILURE.getCode(), "该人员不存在.");
            }
            saveRecordEmpAndSendBroadcast(record.getId(), content, emp,request.getVoiceType());
        }
    }

    @Override
    public PageData<AppHelmetDTO> helmetLatest(Integer pageNum, Integer pageSize, Integer deptId, Integer corpId, Integer groupId, String keyword) {
        logger.info("获取安全帽最新数据服务,pageNum:{},pageSize:{},deptId:{},corpId:{},groupId:{},keyword:{}",
                pageNum, pageSize, deptId, corpId, groupId, keyword);
        PageHelper.startPage(pageNum, pageSize);
        List<AppHelmetDTO> list = appEmpDataMapper.selectHelmetLatestData(deptId, corpId, groupId, keyword);
        PageHelper.clearPage();
        return PageUtil.pageData(PageInfo.of(list));
    }

    @Override
    public PageData<AppHelmetDTO> helmetLog(Integer pageNum, Integer pageSize, Integer deptId, Integer corpId, Integer groupId, String keyword, Date date) {
        logger.info("获取安全帽历史数据服务,pageNum:{},pageSize:{},deptId:{},corpId:{},groupId:{},keyword:{},date:{}",
                pageNum, pageSize, deptId, corpId, groupId, keyword, date);
        List<AppHelmetDTO> list = appEmpMapper.selectHelmet(deptId, corpId, groupId, keyword);
        this.getHelmetLogData(list, date);

        int size = list.size();
        // 分页
        List<AppHelmetDTO> appHelmetDTOS = new ArrayList<>(pageSize);
        int fromIndex = (pageNum - 1) * pageSize;
        int toIndex = pageNum * pageSize;
        if (fromIndex < 0 || fromIndex >= size) {
            return PageUtil.pageData(PageInfo.of(appHelmetDTOS));
        }
        if (toIndex > size) {
            toIndex = size;
        }
        appHelmetDTOS = list.subList(fromIndex, toIndex);

        PageData<AppHelmetDTO> pageData = new PageData<>();
        pageData.setTotal((long) size);
        pageData.setPages(size % pageSize == 0 ? size / pageSize : size / pageSize + 1);
        pageData.setList(appHelmetDTOS);
        return pageData;
    }

    @Override
    public List<AppEmpGroupEmpDTO> helmetEmpList(Integer deptId, String keyword) throws BizException {
        logger.info("查询人员轨迹列表，deptId：{}", deptId);
        List<WxEmpGroupDTO> wxEmpGroupDTOS = appEmpGroupMapper.selectGroupNameByDeptId(deptId);
        List<AppEmpDTO> empList = appEmpMapper.selectHelmetEmpList(deptId, keyword);
        List<AppEmpGroupEmpDTO> list = new ArrayList<>();
        wxEmpGroupDTOS.forEach(wxEmpGroupDTO -> {
            List<AppEmpDTO> appEmpDTOS = new ArrayList<>();
            empList.forEach(appEmpDTO -> {
                if (wxEmpGroupDTO.getGroupId().equals(appEmpDTO.getGroupId()) && StringUtils.isNotEmpty(appEmpDTO.getSn())) {
                    HelmetIconDTO helmetIcon = appEmpDataManager.getHelmetIcon(appEmpDTO.getColor());
                    BeanUtils.copyProperties(helmetIcon, appEmpDTO);
                    appEmpDTOS.add(appEmpDTO);
                }
            });
            if (!appEmpDTOS.isEmpty()) {
                AppEmpGroupEmpDTO appEmpGroupEmpDTO = new AppEmpGroupEmpDTO();
                appEmpGroupEmpDTO.setEmpList(appEmpDTOS);
                appEmpGroupEmpDTO.setGroupId(wxEmpGroupDTO.getGroupId());
                appEmpGroupEmpDTO.setGroupName(wxEmpGroupDTO.getGroupName());
                appEmpGroupEmpDTO.setTotal(appEmpDTOS.size());
                list.add(appEmpGroupEmpDTO);
            }
        });
        return list;
    }

    @Override
    public OssPathDTO helmetLatestDataExport(Integer deptId, Integer corpId, Integer groupId, String keyword) {
        logger.info("导出安全帽最新数据服务,deptId:{},corpId:{},groupId:{},keyword:{}",
                deptId, corpId, groupId, keyword);
        OssPathDTO ossPathDTO = new OssPathDTO();
        // 获取数据
        List<AppHelmetDTO> list = appEmpDataMapper.selectHelmetLatestData(deptId, corpId, groupId, keyword);
        try {
            // 获取模板
            ClassPathResource resource = new ClassPathResource("templates/helmetLatestDataTemplate.xls");
            InputStream templateFileInputStream = resource.getInputStream();
            File tempFile = FileUtil.copyTemplateFile(templateFileInputStream);

            // 写数据
            FileInputStream fileInputStream = new FileInputStream(tempFile);
            HSSFWorkbook workbook = new HSSFWorkbook(fileInputStream);
            HSSFSheet sheet = workbook.getSheetAt(0);

            //填充数据
            int rowIdx = 1;
            for (AppHelmetDTO appDeviceEmpDTO : list) {
                HSSFRow row1 = sheet.createRow(rowIdx);
                Date time = appDeviceEmpDTO.getTime();
                row1.createCell(0).setCellValue(appDeviceEmpDTO.getEmpName());
                row1.createCell(1).setCellValue(appDeviceEmpDTO.getGroupName());
                row1.createCell(2).setCellValue(appDeviceEmpDTO.getCode());
                if (time != null) {
                    row1.createCell(3).setCellValue(DateUtil.formatDate(time, "yyyy-MM-dd HH:mm:ss"));
                }
                rowIdx++;
            }

            //保存excel
            FileOutputStream fos = new FileOutputStream(tempFile);
            workbook.write(fos);
            fos.flush();
            fos.close();

            //上传oss
            String deptName = sysDeptService.getDeptNameById(deptId);
            String name = msFilePathConfig.getFilePath("emp/tmp", String.format("%s安全帽最新数据.xls", deptName));
            FileInputStream inputStream = new FileInputStream(tempFile);
            String upload = fileHandler.upload(name, inputStream, FileExpirationRules.oneDay);
            ossPathDTO.setPath(upload);
        } catch (Exception e) {
            logger.error("安全帽最新数据失败", e);
        }
        return ossPathDTO;
    }

    @Override
    public OssPathDTO helmetLogDataExport(Integer deptId, Integer corpId, Integer groupId, String keyword, Date date) {
        logger.info("导出安全帽历史数据服务,deptId:{},corpId:{},groupId:{},keyword:{},date:{}",
                deptId, corpId, groupId, keyword, date);
        OssPathDTO ossPathDTO = new OssPathDTO();
        // 获取数据
        List<AppHelmetDTO> list = appEmpMapper.selectHelmet(deptId, corpId, groupId, keyword);
        this.getHelmetLogData(list, date);
        try {
            // 获取模板
            ClassPathResource resource = new ClassPathResource("templates/helmetLogDataTemplate.xls");
            InputStream templateFileInputStream = resource.getInputStream();
            File tempFile = FileUtil.copyTemplateFile(templateFileInputStream);

            // 写数据
            FileInputStream fileInputStream = new FileInputStream(tempFile);
            HSSFWorkbook workbook = new HSSFWorkbook(fileInputStream);
            HSSFSheet sheet = workbook.getSheetAt(0);

            //填充数据
            int rowIdx = 1;
            for (AppHelmetDTO appDeviceEmpDTO : list) {
                HSSFRow row1 = sheet.createRow(rowIdx);
                row1.createCell(0).setCellValue(appDeviceEmpDTO.getEmpName());
                row1.createCell(1).setCellValue(appDeviceEmpDTO.getGroupName());
                row1.createCell(2).setCellValue(appDeviceEmpDTO.getCode());

                List<HelmetStatNumDTO> numList = appDeviceEmpDTO.getNumList();
                int i = 3;
                for (HelmetStatNumDTO helmetConnectNumDTO : numList) {
                    row1.createCell(i).setCellValue(helmetConnectNumDTO.getNum());
                    i++;
                }
                rowIdx++;
            }

            //保存excel
            FileOutputStream fos = new FileOutputStream(tempFile);
            workbook.write(fos);
            fos.flush();
            fos.close();

            //上传oss
            String deptName = sysDeptService.getDeptNameById(deptId);
            String name = msFilePathConfig.getFilePath("emp/tmp", String.format("/%s安全帽历史数据(%s).xls", deptName, DateUtil.formatDate(date)));
            FileInputStream inputStream = new FileInputStream(tempFile);
            String upload = fileHandler.upload(name, inputStream, FileExpirationRules.oneDay);
            ossPathDTO.setPath(upload);
        } catch (Exception e) {
            logger.error("安全帽历史数据导出失败", e);
        }
        return ossPathDTO;
    }

    @Override
    public void checkWarn(AppDeviceCardLog log) {
        appEmpDataManager.checkWarn(log);
    }

    @Override
    public String getToken() {
        return zbznVideoApi.getToken();
    }

    @Override
    public void test111(String type) {
        logger.info("emp service impl test111 type:{}", type);
//        zbznVideoApi.login();
        zbznVideoApi.sendMockMsg(type);
    }

    @Override
    public void setHelmetData(String mockData) {
        zbznVideoApi.sendMock(mockData);
    }

    @Override
//    @Scheduled(fixedDelay = 60*1000)
    public void refreshHelmetData(){
        zbznVideoApi.getDeviceInfo();
    }


    /**
     * 统计各时间段硬件通讯次数
     *
     * @param appHelmetDTO
     * @param appDeviceCardLogList
     */
    private void statNum(AppHelmetDTO appHelmetDTO, List<AppDeviceCardLogDTO> appDeviceCardLogList, Date date) {
        Integer empId = appHelmetDTO.getEmpId();
        List<HelmetStatNumDTO> numList = appHelmetDTO.getNumList();

        for (AppDeviceCardLogDTO appDeviceCardLogDTO : appDeviceCardLogList) {
            if (empId.equals(Integer.parseInt(appDeviceCardLogDTO.getEmpId()))) {
                Date startTime = Date.from(appDeviceCardLogDTO.getDeviceTime());
                Integer count = appDeviceCardLogDTO.getCount();
                HelmetStatNumDTO data = new HelmetStatNumDTO();
                data.setNum(count);
                data.setStartTime(startTime);
                data.setEndTime(DateUtil.addHours(startTime, 2));
                numList.add(data);
            }
        }
        Collections.sort(numList, Comparator.comparing(o -> o.getStartTime()));

    }

    /**
     * 获取安全帽历史数据
     *
     * @param list
     * @param date
     * @return
     */
    private List<AppHelmetDTO> getHelmetLogData(List<AppHelmetDTO> list, Date date) {
        if (list.size() == 0) {
            return Collections.emptyList();
        }
        // 查询历史数据
        List<Integer> empIds = new ArrayList<>();
        for (AppHelmetDTO appHelmetDTO : list) {
            appHelmetDTO.setNumList(new ArrayList<>());
            empIds.add(appHelmetDTO.getEmpId());
        }
        Date startTime = DateUtil.getDateBegin(date);
        Date endTime = DateUtil.getDateEnd(date);
        List<AppDeviceCardLogDTO> AppDeviceCardLogList = appEmpDataManager.getHelmetStatByEmpIds(empIds, startTime, endTime);

        // 统计通讯次数
        for (AppHelmetDTO appHelmetDTO : list) {
            this.statNum(appHelmetDTO, AppDeviceCardLogList, date);
        }
        // 去掉当天没上线的
        Iterator<AppHelmetDTO> iterator = list.iterator();
        while (iterator.hasNext()) {
            AppHelmetDTO appHelmetDTO = iterator.next();
            if (appHelmetDTO.getNumList().size() == 0) {
                iterator.remove();
            }
        }
        return list;
    }

    /**
     * 保存接收广播的人员
     *
     * @param recordId 广播记录ID
     * @param emp      人员信息
     */
    private void saveRecordEmpAndSendBroadcast(Integer recordId, String content, AppEmp emp,Integer type) {
        Integer deviceId = emp.getDeviceId();
        if (deviceId == null) {
            throw new BizException(ResultEnum.FAILURE.getCode(), "人员未绑定");
        }
        AppBroadcastRecordEmp recordEmp = new AppBroadcastRecordEmp();
        recordEmp.setEmpId(emp.getId());
        recordEmp.setDeviceId(deviceId);
        recordEmp.setRecordId(recordId);
        recordEmp.setSendTime(new Date());
        recordEmp.setState(AppBroadcastSendState.SEND.getValue());
        recordEmp.setVoiceType(type);
        appBroadcastRecordEmpMapper.insertSelective(recordEmp);
        AppBroadcastRecordEmpDTO recordEmpDTO = new AppBroadcastRecordEmpDTO();
        BeanUtils.copyProperties(recordEmp, recordEmpDTO);
        recordEmpDTO.setContent(content);
        sendBroadcast(recordEmpDTO,type);
    }

    /**
     * 发送广播
     *
     * @param recordEmpDTO 广播DTO
     */
    private void sendBroadcast(AppBroadcastRecordEmpDTO recordEmpDTO,Integer type) {
        AppDeviceDTO appDeviceDTO = appDeviceService.getDeviceById(recordEmpDTO.getDeviceId());
        if (appDeviceDTO == null) {
            return;
        }
        logger.info("得到安全帽硬件数据：{}",appDeviceDTO.toString());
        // 如果是筑邦智能定位安全帽
        if ("zbzn".equals(appDeviceDTO.getExt1())&&appDeviceDTO.getType()==DeviceType.helmet.getValue()) {
            JSONObject jsonData = new JSONObject();
            if (StringUtils.isNotBlank(recordEmpDTO.getContent())) { // 自定义 语音播报
                jsonData = ZbznApi.sendTextToAudio(appDeviceDTO.getSn(), 1,recordEmpDTO.getContent());
            }else {    // 固定播报
                jsonData = ZbznApi.sendVoice(appDeviceDTO.getSn(), type);
            }
            if (200 != jsonData.getInteger("code")) {
                logger.error("发送广播失败", jsonData.getString("message"));
                //修改广播为未发送状态
                appBroadcastRecordEmpMapper.updateState(recordEmpDTO.getId(), AppBroadcastSendState.UNSENT.getValue());
            }
            return;
        }

        recordEmpDTO.setCode(appDeviceDTO.getCode());
        //获取设备Code
        try {
            amqpTemplate.convertAndSend(QueueConst.EMP_HELMET_BOARDCAST, JSON.toJSONString(recordEmpDTO));
        } catch (Exception e) {
            logger.error("发送广播失败", e);
            //修改广播为未发送状态
            appBroadcastRecordEmpMapper.updateState(recordEmpDTO.getId(), AppBroadcastSendState.UNSENT.getValue());
        }
    }
}
